/**
 * 例 9-4
 * raw.c
 * */ 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/ip.h>
#include <linux/tcp.h>

int Open_Raw_Socket(void);                  // 以原始套接字的方式打开
int Set_Promisc(char *interface, int sock); // 设置网卡模式为混杂模式
int main()
{
    int sock;
    int flag = 1;
    sock = Open_Raw_Socket();
    printf("raw socket is %d\n", sock);
    char buffer[65535];
    int bytes_recieved;
    socklen_t fromlen;  // 初始化套接字地址结构长度
    struct sockaddr_in from;
    struct iphdr *ip;
    struct tcphdr *tcp;
    struct in_addr addr;
    // 设置网卡eth0为混杂模式
    Set_Promisc("ens33", sock);
    // 输出TCP/IP报头的长度
    printf("IP header is %ld \n", sizeof(struct iphdr));
    printf("TCP header is %ld \n", sizeof(struct tcphdr));

    while (flag<3)
    {
        fromlen = sizeof(from);
        bytes_recieved = recvfrom(sock, buffer, sizeof(buffer),
                                  0, (struct sockaddr *)&from, &fromlen); // 从原始套接字读取数据
        printf("\nBytes recieved: %5d\n", bytes_recieved);
        printf("Source address: %s\n", inet_ntoa(from.sin_addr));
        ip = (struct iphdr *)buffer; //

        if (ip->protocol == 6)
        {
            // 如果为IPv4协议
            addr.s_addr = ip->daddr;
            printf("Dest address is: %s\n", inet_ntoa(addr));
            printf("IP header Length is :%d\n", ip->tot_len);
            printf("Protocol: %d\n", ip->protocol);
            printf("Type of Server: %d\n", ip->tos);
            printf("Time to live is : %d\n", ip->ttl);
            printf("Check Sum is : %d\n", ip->check);
            tcp = (struct tcphdr *)(buffer + 20);
            //  IP数据包和TCP数据包有20个字节的距离
            printf("Dest port is: %d\n", ntohs(tcp->dest));
            printf("Source port is: %d\n", ntohs(tcp->source));
            printf("Seq number is : %d\n", tcp->seq);
            printf("Ack number is : %d\n", tcp->ack_seq);
            printf("Flags is %d\n", tcp->doff);
        }
        flag++;
    }
    return 0;
}
//  建立一个原始socket句柄
int Open_Raw_Socket(void)
{
    int sock;
    if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
    {
        // 该语句很重要，它告诉我们监听的数据类型
        perror("raw socket create error\n");
        exit(1);
    }
    return sock;
}
// 设置eth0为混杂模式
int Set_Promisc(char *interface, int sock)
{
    struct ifreq ifr;
    strncpy(ifr.ifr_name, interface, strnlen(interface, sizeof(interface)) + 1);
    if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror("set promisc error one if\n");
        exit(1);
    }
    ifr.ifr_flags |= IFF_PROMISC; // 设置网卡为混合模式
    if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror("Can not set PROMISC flag:");
        exit(1);
    }
    return 0;
}
